package com.yami.shop.personnft.common.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.extra.mail.MailException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.yami.shop.bean.enums.SceneType;
import com.yami.shop.bean.enums.TradeType;
import com.yami.shop.bean.event.AddRightsEvent;
import com.yami.shop.bean.event.AssetTrendsEvent;
import com.yami.shop.bean.event.UpdateRightsEvent;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.vo.AssetTrendsVO;
import com.yami.shop.common.bean.Minio;
import com.yami.shop.common.bean.PageDTO;
import com.yami.shop.common.bean.PageVO;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.config.RocketMqConstant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.*;
import com.yami.shop.common.util.pdfUtil.PdfUtils;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.nft.common.model.NftApply;
import com.yami.shop.nft.common.service.NftApplyService;
import com.yami.shop.personnft.common.dao.PersonNftApplyMapper;
import com.yami.shop.personnft.common.dao.PersonNftMapper;
import com.yami.shop.personnft.common.dto.PersonAllClassDto;
import com.yami.shop.personnft.common.model.ExchangeCheckVo;
import com.yami.shop.personnft.common.model.PersonNft;
import com.yami.shop.personnft.common.model.PersonNftAccount;
import com.yami.shop.personnft.common.service.PersonNftAccountService;
import com.yami.shop.personnft.common.service.PersonNftService;
import com.yami.shop.personnft.common.vo.*;
import com.yami.shop.service.*;
import com.yami.shop.user.common.model.UserGasInfo;
import com.yami.shop.user.common.service.UserGasInfoService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class PersonNftServiceImpl implements PersonNftService {
    @Autowired
    private PersonNftMapper personNftMapper;
    @Autowired
    private PersonNftAccountService personNftAccountService;
    @Autowired
    private RocketMQTemplate stockMqTemplate;
    @Autowired
    private PersonNftApplyMapper personNftApplyMapper;
    @Autowired
    private ShopConfig shopConfig;
    @Autowired
    private AttachFileService attachFileService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserGasInfoService userGasInfoService;
    @Autowired
    private ProductService productService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private BusinessNftRecordService businessNftRecordService;
    @Autowired
    private DataWebService dataWebService;
    @Autowired
    private NftApplyService nftApplyService;
    @Autowired
    private ProdNftService prodNftService;
    @Override
    public PersonNft getById(String id) {
        return personNftMapper.getById(id);
    }

    @Override
    public List<PersonNft> listByParam(PersonNft personNft) {
        return personNftMapper.listByParam(personNft);
    }

    @Override
    public Integer listByParamCount(PersonNft personNft) {
        return personNftMapper.listByParamCount(personNft);
    }

    @Override
    public void add(PersonNft personNft) {
        personNft.setStatus(1);
        personNft.setCreateTime(DateUtil.date());
        personNft.setId(IdUtil.getSnowflake().nextIdStr());
        personNftMapper.save(personNft);
    }

    @Override
    public void update(PersonNft personNft) {
        personNft.setUpdateTime(DateUtil.date());
        personNftMapper.update(personNft);
    }

    @Override
    public void deleteById(String id) {
        personNftMapper.deleteById(id);
    }

    @Override
    public IPage<PersonNft> page(PageParam page, PersonNft personNft) {
        return personNftMapper.page(page, personNft);
    }

    @Override
    public PageVO<PersonNftStatisticsVo> getStatistics(PageDTO pageDTO, User user) {
        return PageUtil.doPage(pageDTO, () -> personNftMapper.getPersonNftStatistics(user));
    }

    @Override
    public PageVO<NftPersonVO> getPositionByUserId(PageDTO pageDTO, NftPersonVO nftPersonVO) {
        return PageUtil.doPage(pageDTO, () -> personNftMapper.getPersonNftByUserId(nftPersonVO));
    }

    @Override
    @Transactional
    public void addPersonnftByBuy(BusinessNft businessNft) {
        List<PersonNft> savePersonNftList = new ArrayList<>();
        Product productByProdId = null;
        if(businessNft.getBusinessType() != 10){
            productByProdId = productService.getProductByProdId(Long.valueOf(businessNft.getProdId()));
        }
        Double price = null;
        Integer sceneType= null;
        Integer tradeType = null;
        if (businessNft.getBusinessType() == 0) {
            // 订单
            Order orderAndOrderItemByOrderId = orderService.getOrderAndOrderItemByOrderId(Long.valueOf(businessNft.getOutId()));
            price = orderAndOrderItemByOrderId.getOrderItems().get(0).getPrice();
            sceneType= Integer.valueOf(SceneType.AddByOrder.getCode());
            tradeType = TradeType.PLACE_ORDER.getValue();
        } else if (businessNft.getBusinessType() == 1) {
            //开盲盒
            price = 0.0;
            sceneType= Integer.valueOf(SceneType.OPEN_HOLD.getCode());
            tradeType = TradeType.OPEN_HOLD.getValue();
        } else if (businessNft.getBusinessType() == 2) {
            //合成

        } else if (businessNft.getBusinessType() == 4) {
            // 零元购
            price = 0.0;
            sceneType= Integer.valueOf(SceneType.OrderZERO.getCode());
            tradeType = TradeType.PLACE_ZERO.getValue();
        }else if (businessNft.getBusinessType() == 5) {
            // 提现空投
            price = 0.0;
            sceneType= Integer.valueOf(SceneType.AddByMarket.getCode());
            tradeType = TradeType.ROLL_IN_AIRDROP.getValue();
        } else if (businessNft.getBusinessType() == 9) {
            // 空投
            price = 0.0;
            sceneType= Integer.valueOf(SceneType.AddByGive.getCode());
            tradeType = TradeType.AIRDROP.getValue();
        } else if (businessNft.getBusinessType() == 10) {
            // mall4j订单
            price = 0.0;
            sceneType= Integer.valueOf(SceneType.AddByMallOrder.getCode());
            tradeType = TradeType.PLACE_MAll_ORDER.getValue();
        }

        List<BusinessNftRecord> businessNftRecordAllList = businessNftRecordService.list(new LambdaQueryWrapper<BusinessNftRecord>().eq(BusinessNftRecord::getBusinessNftId, businessNft.getBusinessNftId()).eq(BusinessNftRecord::getStatus, 0));
        if(businessNftRecordAllList.isEmpty()){
            throw new MailException("没有可空投的币");
        }
        //拆分 每次存储处理1000个
        List<List<BusinessNftRecord>> businessNftRecordBatchaList = Lists.partition(businessNftRecordAllList, 1000);
        for (List<BusinessNftRecord> businessNftRecordList :businessNftRecordBatchaList) {
            // 创建资产记录,用于资产对账
            List<AssetTrendsVO> list = new ArrayList<>();
            for (BusinessNftRecord businessNftRecord : businessNftRecordList) {
                PersonNft personNft = PersonNft.builder()
                        .id(IdUtil.getSnowflake().nextIdStr())
                        .denomId(businessNftRecord.getDenomId())
                        .createTime(new Date()).status(0)
                        .userId(businessNftRecord.getUserId())
                        .tokenId(businessNftRecord.getDawId())
                        .sceneType(sceneType).build();
                if(businessNft.getBusinessType() != 10 && businessNft.getBusinessType() != 11){
                    String spucode = businessNftRecord.getProdId() + "#" + businessNftRecord.getNftCode();
                    personNft.setChainCode(productByProdId.getChain());
                    personNft.setChannelCode(productByProdId.getChannelCode());
                    personNft.setProductId(Long.valueOf(businessNftRecord.getProdId()));
                    personNft.setDawProductCode(spucode);
                    // 获取源文件信息 -- 判断是否需要 替换 源文件
                    NftApply nftApply = nftApplyService.getNftApplyAndImgInfoByDenomId(businessNftRecord.getDenomId());
                    if(nftApply.getNftApplyImg().getIsReplaceUrl() == 1 ){
                        // 获取用户 实名 信息
                        User user = userService.getUserByUserId(businessNftRecord.getUserId());
                        // 上传文件信息
                        String sourceUrlPdf = JSONObject.parseObject(nftApply.getNftApplyImg().getImgUrl()).getString("sourceUrlPdf");
                        Map<String, Object> keyWordMap = new HashMap<>();
                        keyWordMap.put("name",user.getRealName());

                        keyWordMap.put("worksNo","dtc"+ StrUtil.padPre(String.valueOf(personNft.getId()),20,"0"));
                        keyWordMap.put("worksTypeName","字画");
                        keyWordMap.put("time",DateUtil.formatDateTime(personNft.getCreateTime()));
                        keyWordMap.put("tokenId",personNft.getTokenId());
                        Minio minio = shopConfig.getMinio();
                        Map<String,String> imageMap = new HashMap<>();
                        if(ObjectUtil.isNotEmpty(businessNft.getMainProdId())){
                            Product byId = productService.getProductByProdId(Long.parseLong(businessNft.getMainProdId()));
                            keyWordMap.put("worksName",byId.getProdName());
                            imageMap.put("worksImg",minio.getEndpoint() + "/" + minio.getBucketName() + "/" + byId.getPic());
                            ProdNft prodNft = prodNftService.getDataByProdId(Long.parseLong(businessNft.getMainProdId()));
                            keyWordMap.put("autherName",prodNft.getAuthorName());
                        }else{
                            keyWordMap.put("worksName",productByProdId.getProdName());
                            imageMap.put("worksImg",minio.getEndpoint() + "/" + minio.getBucketName() + "/" + productByProdId.getPic());
                            ProdNft prodNft = prodNftService.getDataByProdId(productByProdId.getProdId());
                            keyWordMap.put("autherName",prodNft.getAuthorName());
                        }

                        String sourceUrl = updateSourceImg(imageMap,keyWordMap,sourceUrlPdf);
                        personNft.setSourceUrl(sourceUrl);
                    }
                }else{
                    Object o = RedisUtil.get("applyIssue::" + businessNft.getProdId());
                    if(ObjectUtil.isNull(o)){
                        getApplyIssueNftInfoByDenomId(businessNft.getProdId());
                        o = RedisUtil.get("applyIssue::" + businessNft.getProdId());
                    }
                    JSONObject obj = JSONObject.parseObject(o.toString());
                    String spucode = businessNft.getProdId().substring(businessNft.getProdId().length()-6) + "#" + businessNftRecord.getNftCode(); //denomId截取
                    personNft.setChainCode(obj.getString("chainCode"));
                    personNft.setChannelCode(obj.getString("channelCode"));
                    personNft.setDawProductCode(spucode);
                    personNft.setProductName(obj.getString("dawName"));
                    personNft.setSourceUrl(obj.getString("imgUrl"));
                    personNft.setProductId(0L);
                }
                // 持仓
                savePersonNftList.add(personNft);
                // 账单
                log.info("新增资产动向记录=================");
                AssetTrendsVO trendsVO = AssetTrendsVO.builder().denomId(businessNftRecord.getDenomId()).tokenId(businessNftRecord.getDawId()).fromUserId(null).toUserId(businessNftRecord.getUserId()).price(price).outId(businessNft.getOutId()).build();
                // 增加权益
                log.info("新增资产动向记录=================增加权益信息");
                if(businessNft.getBusinessType() != 10) {
                    trendsVO.setProdId(Long.valueOf(businessNftRecord.getProdId()));
                    applicationContext.publishEvent(new AddRightsEvent(Long.parseLong(businessNftRecord.getProdId()), businessNftRecord.getUserId(), businessNftRecord.getDawId(),null));
                }else{
                    trendsVO.setProdId(0L);
                }
                list.add(trendsVO);
            }
            String code = businessNftRecordList.stream().map(s -> businessNft.getBusinessType() != 10 ? businessNft.getProdId():businessNft.getProdId().substring(businessNft.getProdId().length() - 6) + "#" + s.getNftCode()).collect(Collectors.joining(","));
            String tokens = businessNftRecordList.stream().map(BusinessNftRecord::getDawId).collect(Collectors.joining(","));
            // 账单处理
            PersonNftAccount personNftAccount = PersonNftAccount.builder().sceneType(sceneType).content(tokens).dawProductCode(code).orderId(businessNft.getOutId()).count(businessNft.getNum()).type(1).userId(businessNft.getUserId()).shortUrl(null).denomId(businessNftRecordList.get(0).getDenomId()).channelType("1").build();
            if(businessNft.getBusinessType() != 10){
                personNftAccount.setChainCode(productByProdId.getChain());
                personNftAccount.setChannelCode(productByProdId.getChannelCode());
                personNftAccount.setProductId(Long.valueOf(businessNft.getProdId()));
            }else{
                Object o = RedisUtil.get("applyIssue::" + businessNft.getProdId());
                if(ObjectUtil.isNull(o)){
                    getApplyIssueNftInfoByDenomId(businessNft.getProdId());
                    o = RedisUtil.get("applyIssue::" + businessNft.getProdId());
                }
                JSONObject obj = JSONObject.parseObject(o.toString());
                personNftAccount.setChainCode(obj.getString("chainCode"));
                personNftAccount.setChannelCode(obj.getString("channelCode"));
                personNftAccount.setProductId(0L);
            }
            personNftMapper.saveBatch(savePersonNftList);
            personNftAccountService.save(personNftAccount);
            applicationContext.publishEvent(new AssetTrendsEvent(tradeType, list));


        }
    }
    @Override
    @Transactional
    public void addPersonnftByShare(BusinessNft businessNft) {
        //新增持仓
        List<PersonNft> lsitAdd = new ArrayList<>();
        //修改持仓
        List<PersonNft> lsit = new ArrayList<>();
        List<AssetTrendsVO> listAsset = new ArrayList<>();
        Object o = RedisUtil.get("applyIssue::" + businessNft.getProdId());
        if(ObjectUtil.isNull(o)){
            getApplyIssueNftInfoByDenomId(businessNft.getProdId());
            o = RedisUtil.get("applyIssue::" + businessNft.getProdId());
        }
        JSONObject obj = JSONObject.parseObject(o.toString());
        PersonNft personNft = PersonNft.builder().denomId(businessNft.getProdId()).status(0).userId(businessNft.getFromUserId()).build();
        PageParam page = new PageParam();
        page.setCurrent(1);
        page.setSize(businessNft.getNum());
        IPage<PersonNft> page1 = personNftMapper.page(page, personNft);
        if(page1.getTotal() < businessNft.getNum()){
            throw new MailException("持仓币不足");
        }
        List<PersonNft> records = page1.getRecords();
        String tokenIds = records.stream().map(PersonNft::getTokenId).collect(Collectors.joining(","));
        String dawProductCodes = records.stream().map(PersonNft::getDawProductCode).collect(Collectors.joining(","));
        // mall4j订单
        PersonNftApply personNftApply = PersonNftApply.builder()
                .createTime(DateUtil.date()).id(IdUtil.getSnowflake().nextIdStr())
                .content(tokenIds).dawProductCode(dawProductCodes)
                .sceneType("1").status(1).count(businessNft.getNum())
                .denomId(businessNft.getProdId()).productId(0L)
                .userId(businessNft.getFromUserId()).toUserId(businessNft.getUserId())
                .channelCode(obj.getString("channelCode"))
                .updateTime(DateUtil.date()).chainCode(obj.getString("chainCode"))
                .channelType("1").build();
        personNftApplyMapper.save(personNftApply);

        records.forEach(s->{
            //1增加受赠方持仓
            PersonNft personNft1 = PersonNft.builder().tokenId(s.getTokenId()).userId(businessNft.getUserId()).build();
            List<PersonNft> personNfts = personNftMapper.listByParam(personNft1);
            //校验受赠方是否有该未删除的tokenid
            List<PersonNft> list = personNfts.stream().filter(m -> m.getStatus()!=2).collect(Collectors.toList());
            if(list.size()>1){
                log.info("接收-受赠方持仓数据异常，业务记录id="+businessNft.getBusinessNftId());
                throw new YamiShopBindException("受赠方持仓数据异常");
            }
            List<PersonNft> list1 = personNfts.stream().filter(m -> m.getStatus()==2).collect(Collectors.toList());
            if(!list1.isEmpty()){
                //如果受赠方已有记录直接修改状态
                PersonNft personNft2 = list1.get(0);
                personNft2.setUserId(businessNft.getUserId());
                personNft2.setStatus(0);
                personNft2.setSceneType(Integer.valueOf(SceneType.AddByTransfer.getCode()));
                personNft2.setUpdateTime(DateUtil.date());
                personNft2.setCreateTime(DateUtil.date());
                lsit.add(personNft2);
            }else{
                //受赠方添加持仓 -没有新增一条
                PersonNft person = PersonNft.builder()
                        .status(0)
                        .id(IdUtil.getSnowflake().nextIdStr())
                        .createTime(DateUtil.date())
                        .userId(businessNft.getUserId())
                        .tokenId(s.getTokenId())
                        .productId(s.getProductId())
                        .dawProductCode(s.getDawProductCode())
                        .denomId(s.getDenomId())
                        .channelCode(s.getChannelCode())
                        .chainCode(s.getChainCode())
                        .sceneType(Integer.valueOf(SceneType.AddByTransfer.getCode()))
                        .sourceUrl(s.getSourceUrl())
                        .productName(s.getProductName())
                        .build();
                lsitAdd.add(person);
            }
            //受赠方减去持仓
            s.setStatus(2);
            s.setUpdateTime(DateUtil.date());
            lsit.add(s);

            AssetTrendsVO trendsVO = AssetTrendsVO.builder().denomId(s.getDenomId()).tokenId(s.getTokenId())
                    .fromUserId(businessNft.getFromUserId()).toUserId(businessNft.getUserId())
                    .price(0.0).outId(personNftApply.getId()).prodId(personNftApply.getProductId()).build();
            listAsset.add(trendsVO);
        });
        //保存持仓或者删除持仓
        if(!lsit.isEmpty()){
            personNftMapper.updateBatchById(lsit);
        }
        if(!lsitAdd.isEmpty()){
            personNftMapper.saveBatch(lsitAdd);
        }

        //2增加受赠方藏品记录
        PersonNftAccount personNftAccount = PersonNftAccount.builder()
                .sceneType(Integer.valueOf(SceneType.AddByTransfer.getCode()))
                .content(personNftApply.getContent())
                .dawProductCode(personNftApply.getDawProductCode())
                .channelType(personNftApply.getChannelType())
                .denomId(personNftApply.getDenomId())
                .userId(personNftApply.getToUserId())
                .createTime(DateUtil.date())
                .id(cn.hutool.core.util.IdUtil.getSnowflake().nextIdStr())
                .count(personNftApply.getCount())
                .productId(personNftApply.getProductId())
                .channelCode(personNftApply.getChannelCode())
                .chainCode(personNftApply.getChainCode())
                .type(1)
                .orderId(personNftApply.getId())
                .build();
        personNftAccountService.save(personNftAccount);
        //5 转增方转增记录
        PersonNftAccount personNftAccount1 = PersonNftAccount.builder()
                .sceneType(Integer.valueOf(SceneType.ReduceByTransfer.getCode()))
                .content(personNftApply.getContent())
                .dawProductCode(personNftApply.getDawProductCode())
                .channelType(personNftApply.getChannelType())
                .denomId(personNftApply.getDenomId())
                .userId(personNftApply.getUserId())
                .createTime(DateUtil.date())
                .id(IdUtil.getSnowflake().nextIdStr())
                .count(personNftApply.getCount())
                .productId(personNftApply.getProductId())
                .channelCode(personNftApply.getChannelCode())
                .type(1)
                .chainCode(personNftApply.getChainCode())
                .orderId(personNftApply.getId())
                .build();
        personNftAccountService.save(personNftAccount1);
        log.info("转增修改持仓完成=================进入转赠记账");
        //6发起转增记账
        applicationContext.publishEvent(new AssetTrendsEvent(TradeType.RE_GIFT.getValue(), listAsset));
    }
    private String updateSourceImg(Map<String,String> imageMap,Map<String, Object> keyWordMap, String sourceUrlPdf) {
        try{
            Minio minio = shopConfig.getMinio();
            URL url = new URL(minio.getEndpoint() + "/" + minio.getBucketName() + "/" + sourceUrlPdf);
            URLConnection urlConnection = url.openConnection();
            urlConnection.connect();
            ByteArrayOutputStream qrOutputStream = new ByteArrayOutputStream();
            // 85f
            PdfUtils.generatePdf(urlConnection.getInputStream(), qrOutputStream, keyWordMap,imageMap,35f);
            //保存图片
            PDDocument document = PDDocument.load(qrOutputStream.toByteArray());
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            BufferedImage image = pdfRenderer.renderImageWithDPI(0, 300); // 使用300dpi解析第一页，可以自行调整dpi大小
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ByteArrayOutputStream scaleOutputStream = new ByteArrayOutputStream();
            ImageIO.write(image, "JPEG", outputStream);
            MultipartFile ossMultipartFile = new OssMultipartFile("111.jpg", ".jpg", outputStream.toByteArray());
            ImgUtil.scale(ossMultipartFile.getInputStream(),scaleOutputStream,0.1f);
            return attachFileService.uploadFile(scaleOutputStream.toByteArray(), UUID.randomUUID() + ".jpg");
        }catch (Exception e){
            log.error("PDF生成异常{}",e);
            return "";
        }
    }

    @Override
    public IPage<PersonAllClassDto> getAllClassListByShop(PageParam<PersonNft> page, PersonNft personNft) {
        page.setOptimizeCountSql(false);
        return personNftMapper.getAllClassListByShop(page, personNft);
    }


    @Override
    public void saveBatch(List<PersonNft> list) {
        personNftMapper.saveBatch(list);
    }

    @Override
    public void updateBatch(List<PersonNft> list) {
        personNftMapper.updateStatusBatchById(list);
    }

    @Override
    public void updateBatchById(List<PersonNft> list) {
        personNftMapper.updateBatchById(list);
    }

    @Override
    public IPage<Map<String, Object>> getAllClassList(PageParam page, PersonNft personNft) {
        return personNftMapper.getAllClassList(page, personNft);
    }
    @Override
    public IPage<Map<String, Object>> getAllClassList2(PageParam page, PersonNft personNft) {
        return personNftMapper.getAllClassList2(page, personNft);
    }
    @Override
    public List<PersonTreeVO>  getAllClassTreeList(PersonNft personNft) {
        return personNftMapper.getAllClassTreeList(personNft);
    }
    @Override
    public List<PersonTreeVO>  getAllClassTreeList2(PersonNft personNft) {
        return personNftMapper.getAllClassTreeList2(personNft);
    }
    @Override
    public Map<String, Object> getOneClass(Long productId) {
        return personNftMapper.getOneClass(productId);
    }

    @Override
    public PersonNftDtailfVo getOneDetail(PersonNft personNft) {
        return personNftMapper.getOneDetail(personNft);
    }
    @Override
    public PersonNftDtailfVo getOneDetail1(PersonNft personNft) {
        return personNftMapper.getOneDetail1(personNft);
    }
    @Override
    public JSONObject transferToOthersAllCount(PersonNft personNft) {
        JSONObject jSONObject = new JSONObject();
        Map<String, Integer> stringIntegerMap = personNftMapper.listByParamTransferOtherCount(personNft);
        jSONObject.put("transferCount", stringIntegerMap.get("transferCount"));
        jSONObject.put("transferNoCount", stringIntegerMap.get("transferNoCount"));
        jSONObject.put("transferYesCount", stringIntegerMap.get("transferYesCount"));
        Integer gas = 0;
        UserGasInfo one = userGasInfoService.getOne(new LambdaQueryWrapper<UserGasInfo>().eq(UserGasInfo::getUserId, personNft.getUserId()));
        if (one != null) {
            gas = one.getGasNumber();
        }
        jSONObject.put("gasCount", gas);
        return jSONObject;
    }

    @Override
    public JSONObject transferAllCount(PersonNft personNft) {
        JSONObject jSONObject = new JSONObject();
        if (personNft.getDay() == null || personNft.getDay() == 0L) {//不冻结，t+n ，兑换权益没有使用过
            Map<String, Integer> stringIntegerMap = personNftMapper.listByParamTransferCount(personNft);
            jSONObject.put("transferCount", stringIntegerMap.get("transferCount"));
            jSONObject.put("transferNoCount", stringIntegerMap.get("transferNoCount"));
            jSONObject.put("transferYesCount", stringIntegerMap.get("transferYesCount"));
        } else {
            Map<String, Long> stringIntegerMap = personNftMapper.listByParamTransferToOtherCount(personNft);
            Integer allCount = 0;
            if (!Objects.isNull(stringIntegerMap.get("allCount"))) {
                allCount = Integer.valueOf(stringIntegerMap.get("allCount").toString());
            }
            Integer transferCount = 0;
            if (!Objects.isNull(stringIntegerMap.get("transferCount"))) {
                transferCount = Integer.valueOf(stringIntegerMap.get("transferCount").toString());
            }
            jSONObject.put("transferCount", allCount);
            jSONObject.put("transferNoCount", allCount - transferCount);
            jSONObject.put("transferYesCount", transferCount);
        }
        Integer gas = 0;
        UserGasInfo one = userGasInfoService.getOne(new LambdaQueryWrapper<UserGasInfo>().eq(UserGasInfo::getUserId, personNft.getUserId()));
        if (one != null) {
            gas = one.getGasNumber();
        }
        jSONObject.put("gasCount", gas);
        return jSONObject;
    }


    @Override
    public void thansfer(List<ThansferVo> list) {
        for (ThansferVo thansferVo : list) {
            // 发起mq修改资产
            Map<String, String> nft = new HashMap<>();
            nft.put("denomId", thansferVo.getDenomId());
            nft.put("nftId", thansferVo.getTokenId());
            nft.put("userId", thansferVo.getUserId());
            if (RocketMqConstant.NFT_OUT_SHIFT.equals(thansferVo.getTypeMq())) {
                nft.put("mnemonic", thansferVo.getMnemonic());
            } else if (RocketMqConstant.NFT_Into_SHIFT.equals(thansferVo.getTypeMq())) {
                nft.put("reci", thansferVo.getAddress());
            }
            log.info("托管账户通知修改资产变更=======================");
            SendStatus stockSendStatus = stockMqTemplate.syncSend(thansferVo.getTypeMq(), new GenericMessage<>(nft)).getSendStatus();
            if (!Objects.equals(stockSendStatus, SendStatus.SEND_OK)) {
                // 消息发不出去就抛异常，发的出去无所谓
                throw new MailException("划转资产通知异常");
            }
            log.info("托管账户通知修改资产变更通知结束=================");
        }
    }


    /**
     * 商城转出资产转移
     *
     * @param id
     */
    @Override
    public void sendDeletePersonNftMqData(String id) {
        PersonNftApply personNftApply = personNftApplyMapper.getinfoById(id);
        User user = userService.getUserByUserId(personNftApply.getUserId());
        if (StringUtils.isEmpty(user.getMnemonic())) {
            throw new MailException("用户没有实名");
        }
        List<String> strlist = Arrays.asList(personNftApply.getContent().split(","));
        for (String tokenId : strlist) {
            // 6发起mq修改资产
            Map<String, String> nft = new HashMap<>();
            nft.put("denomId", personNftApply.getDenomId());
            nft.put("nftId", tokenId);
            nft.put("userId", personNftApply.getUserId() + "");
            nft.put("mnemonic", user.getMnemonic());
            nft.put("address", user.getDtcdawAddress());
            log.info("托管账户通知修改资产变更=======================");
            SendStatus stockSendStatus = stockMqTemplate.syncSend(RocketMqConstant.NFT_OUT_SHIFT, new GenericMessage<>(nft)).getSendStatus();
            if (!Objects.equals(stockSendStatus, SendStatus.SEND_OK)) {
                // 消息发不出去就抛异常，发的出去无所谓
                log.error("托管账户通知修改资产变更通知失败:{}", JSON.toJSONString(nft));
            }
            log.info("托管账户通知修改资产变更通知结束=================");
        }
    }

    @Override
    public Map<String, Object> exchangeNftCheck(ExchangeCheckVo exchangeCheckVo) {
        // 1更加商品获取规则
        Map<String, Object> obj = new HashMap<>();
//		EquityVo equityVo = equityService.getEquityListBySkuId(exchangeCheckVo.getSkuId());
        List<PersonNft> personNftList = personNftMapper.getListByIds(exchangeCheckVo.getPersonNftIds().toArray(new String[]{}));
        for (PersonNft personNft : personNftList) {
            if (personNft.getStatus() != 0) {
                obj.put("code", "1");
                obj.put("msg", "持仓数据状态异常");
                return obj;
            }
            if (!"0".equals(personNft.getRemark())) {
                obj.put("code", "2");
                obj.put("msg", "持仓资产接收中，稍后再兑换");
                return obj;
            }
        }

        // 获取材料需要兑换的数量
        Integer count = 0;// equityVo.getExchangeRules();
        if (count * exchangeCheckVo.getCount() != exchangeCheckVo.getOrderExchangeNfts().size()) {
            log.info("count:{}:num{},allCount:{}", count, exchangeCheckVo.getCount(), exchangeCheckVo.getOrderExchangeNfts().size());
            obj.put("code", "3");
            obj.put("msg", "选择的数量和所需数量不一致");
            return obj;
        }
        String userId = exchangeCheckVo.getUserId();
        List<OrderExchangeNft> list = exchangeCheckVo.getOrderExchangeNfts();
        List<String> tokenIds = list.stream().map(OrderExchangeNft::getTokenId).collect(Collectors.toList());
        // 两种类型一样（1:不指定币2:指定币）
        List<PersonNft> checklist = personNftMapper.getListByTokenIdsAnduserId(tokenIds, userId);
        if (checklist.size() != list.size()) {
            obj.put("code", "4");
            obj.put("msg", "数据异常：选择的材料持仓不够");
            return obj;
        }
        obj.put("code", "0");
        obj.put("msg", "ok");
        return obj;
    }

    @Override
    public List<PersonNft> getPersonNftNormalStatusList(List<String> personIds) {
        if (ObjectUtil.isEmpty(personIds)) {
            throw new MailException("tokenIds不能为空");
        }
        List<PersonNft> personNfts = personNftMapper.getPersonNftDataList(personIds);
        return personNfts;
    }

    @Override
    public List<PersonNft> getPersonNftList(List<String> personIds) {
        if (CollUtil.isEmpty(personIds)) {
            throw new MailException("personIds不能为空");
        }
        List<PersonNft> list = personNftMapper.getListByIds(personIds.toArray(new String[]{}));
        return list;
    }

    @Override
    public void updatePersonNftStatus(List<String> personIds, Integer status) {
        personNftMapper.updatePersonNftStatus(personIds, status);
    }

    /**
     * 提现增加持仓
     *
     * @param appId
     */
    @Override
    public void addPersonNft(String appId) {
        PersonNftApply personNftApply = personNftApplyMapper.getinfoById(appId);
        List<String> strlist = Arrays.asList(personNftApply.getContent().split(","));
        // 持仓
        List<PersonNft> personNftList1 = new ArrayList<>();
        // 修改持仓 划转出去又提现回原来账户
        List<PersonNft> personNftList2 = new ArrayList<>();
        // 单独处理业务
        List<AssetTrendsVO> trends = new ArrayList<>();
        for (String tokenId : strlist) {
            // 判断tokenid用户是否存在该用户名下
            PersonNft param = PersonNft.builder().tokenId(tokenId).status(2).build();
            List<PersonNft> personNftList = personNftMapper.listByParam(param);
            PersonNft personNft = personNftList.stream().sorted(Comparator.comparing(PersonNft::getUpdateTime).reversed()).collect(Collectors.toList()).get(0);
            String fromUserId = personNft.getUserId();
            PersonNft resPersonNft = null;
            // 根据结果查询
            if (!personNftList.isEmpty()) {
                // 根据查询出来的持仓集合过滤是否有改用户的
                List<PersonNft> collect = personNftList.stream().filter(nft -> nft.getUserId().equals(personNftApply.getUserId())).collect(Collectors.toList());
                log.info("本持仓中包含token个数" + collect.size());
                if (collect != null && collect.size() >= 1) {
                    resPersonNft = collect.get(0);
                    resPersonNft.setStatus(0);
                    resPersonNft.setUpdateTime(DateUtil.date());
                    resPersonNft.setCreateTime(DateUtil.date());
                    personNftList2.add(resPersonNft);
                } else {
                    // 名下没有
                    resPersonNft = personNftList.get(0);
                    resPersonNft.setStatus(0);
                    resPersonNft.setId(IdUtil.getSnowflake().nextIdStr());
                    resPersonNft.setCreateTime(DateUtil.date());
                    resPersonNft.setUserId(personNftApply.getUserId());
                    personNftList1.add(resPersonNft);
                }
            } else {
                throw new MailException("该tokenid持仓异常");
            }
            // 记账DOTO
            AssetTrendsVO trendVO = AssetTrendsVO.builder().denomId(personNftApply.getDenomId()).tokenId(tokenId).toUserId(personNftApply.getUserId()).price(0.00).outId(appId).prodId(personNftApply.getProductId()).build();
            trends.add(trendVO);
            log.info("权益转移{}-》{}",fromUserId,personNftApply.getUserId());
            if(!fromUserId.equals(personNftApply.getUserId())){
                try {
                    applicationContext.publishEvent(new UpdateRightsEvent(tokenId, fromUserId, personNftApply.getUserId()));
                }catch (Exception e){
                    log.error("权益转移失败tokenId={}，{}",tokenId,e.getMessage());
                }
            }
        }
        // 账单处理
        PersonNftAccount personNftAccount = PersonNftAccount.builder().sceneType(Integer.valueOf(SceneType.AddByMarket.getCode())).content(personNftApply.getContent()).channelType(personNftApply.getChannelType()).chainCode(personNftApply.getChainCode()).channelCode(personNftApply.getChannelCode()).dawProductCode(personNftApply.getDawProductCode()).denomId(personNftApply.getDenomId()).userId(personNftApply.getUserId()).createTime(DateUtil.date()).id(IdUtil.getSnowflake().nextIdStr()).count(personNftApply.getCount()).productId(personNftApply.getProductId()).build();
        personNftAccountService.save(personNftAccount);
        if (!personNftList1.isEmpty()) {
            personNftMapper.saveBatch(personNftList1);
        }
        if (!personNftList2.isEmpty()) {
            personNftMapper.updateBatchById(personNftList2);
        }
        applicationContext.publishEvent(new AssetTrendsEvent(TradeType.ROLL_IN.getValue(), trends));
    }

    /**
     * 划转删除持仓
     *
     * @param id
     */
    @Override
    public void deleteThanserPersonNft(String id) {
        PersonNftApply personNftApply = personNftApplyMapper.getinfoById(id);
        List<String> strlist = Arrays.asList(personNftApply.getContent().split(","));
        for (String tokenId : strlist) {
            // 持仓删除
            if("1".equals(personNftApply.getChannelType())){
                List<PersonNft> PersonNftList = new ArrayList<>();
                PersonNft personNft = PersonNft.builder().tokenId(tokenId).userId(personNftApply.getUserId()).status(1).build();
                List<PersonNft> personNfts2 = personNftMapper.listByParam(personNft);
                if (personNfts2.size() != 1) {
                    log.info("审核-划转持仓数据异常，转增记录id=" + id);
                    throw new MailException("划转持仓数据异常");
                } else {
                    // 转出方删除
                    PersonNft personNft1 = personNfts2.get(0);
                    personNft1.setStatus(2);
                    personNft1.setUpdateTime(DateUtil.date());
                    PersonNftList.add(personNft1);
                }
                personNftMapper.updateBatchById(PersonNftList);
            }else{
                //下游通知删除持仓
                Map<String,String> obj = new HashMap<>();
                obj.put("id",personNftApply.getDownApplyId());
                obj.put("type","2");
                obj.put("channelCode",personNftApply.getChannelCode());
                String url = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/personnftApply/transferPerson?";
                JSONObject jsonObject = dataWebService.hutoolPostWebService(url, obj,null,null);
                if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
                    log.info("获取{}",jsonObject.getString("msg"));
                    throw new YamiShopBindException(jsonObject.getString("msg"));
                }
            }
        }
        // 持仓台账记录增加
        PersonNftAccount personNftAccount = PersonNftAccount.builder().sceneType(Integer.valueOf(SceneType.ReduceByMarket.getCode())).content(personNftApply.getContent()).dawProductCode(personNftApply.getDawProductCode()).channelType(personNftApply.getChannelType()).chainCode(personNftApply.getChainCode()).channelCode(personNftApply.getChannelCode()).denomId(personNftApply.getDenomId()).userId(personNftApply.getUserId()).createTime(DateUtil.date()).id(IdUtil.getSnowflake().nextIdStr()).count(strlist.size()).productId(personNftApply.getProductId()).build();
        personNftAccountService.save(personNftAccount);
    }

    @Override
    public List<String> frozenByTokenId(String tokenId) {
        PersonNft personNft = PersonNft.builder().tokenId(tokenId).status(0).build();
        personNft.setTokenId(tokenId);
        personNft.setStatus(0);
        List<PersonNft> list = personNftMapper.listByParam(personNft);
        if (CollUtil.isEmpty(list)) {
            return null;
        }
        list.forEach(p -> {
            p.setStatus(1);
        });
        personNftMapper.updateStatusBatchById(list);
        List<String> userIds = list.stream().map(PersonNft::getUserId).collect(Collectors.toList());
        return userIds;
    }

    public static void main(String[] args) {try{
//            Minio minio = shopConfig.getMinio();
//            URL url = new URL(minio.getEndpoint() + "/" + minio.getBucketName() + "/" +sourceUrlPdf);
//            URLConnection urlConnection = url.openConnection();
//            urlConnection.connect();
        // 1、读取PDF模板文件
//            PDDocument document = PDDocument.load(urlConnection.getInputStream());
        ByteArrayOutputStream qrOutputStream = new ByteArrayOutputStream();
        File pdfFile = new File("E:\\test\\22222.pdf");
        Map<String,Object> mapData = new HashMap<>();
        mapData.put("name","李世荣");
        PdfUtils.generatePdf(new FileInputStream(pdfFile),qrOutputStream,mapData,null,85f);

        File imageFile = new File("E:\\test\\3333.pdf");
        //File imageFile = new File("/data/images/"+localFileName);
        //创建输出流
        FileOutputStream fileOutputStream = new FileOutputStream(imageFile);
        //写入数据
        fileOutputStream.write(qrOutputStream.toByteArray());
        //关闭输出流
        fileOutputStream.close();


        //        File pdfFile2 = new File("E:\\test\\44444.pdf");
//        PDDocument document = PDDocument.load(new FileInputStream(pdfFile2));
        PDDocument document = PDDocument.load(qrOutputStream.toByteArray());
        PDFRenderer pdfRenderer = new PDFRenderer(document);
        BufferedImage image = pdfRenderer.renderImageWithDPI(0, 300); // 使用300dpi解析第一页，可以自行调整dpi大小

        ImageIO.write(image, "JPEG", new File("E:\\test\\3333.jpg"));




//        ImageIO.write(image, "JPEG", new File("E:\\test\\test.jpg"));

        //保存图片
//            ByteArrayOutputStream qrOutputStream = new ByteArrayOutputStream();
//            //读文件
//            ImageIO.write(image,"jpg",qrOutputStream);
//            MultipartFile ossMultipartFile = new OssMultipartFile("111.jpg", ".jpg", qrOutputStream.toByteArray());
//            String fileName = attachFileService.uploadFile(ossMultipartFile.getBytes(), UUID.fastUUID()+".jpg");
        // 关闭文档
//            return fileName;
    }catch (Exception e){
        System.out.println(e);
    }
    }

    @Override
    public void getApplyIssueNftInfoByDenomId(String denomId) {
        log.info("获取缓存铸币信息"+denomId);
        String urlInfo = shopConfig.getApiGatewayUrl() + "/nft/outapi/api/nftcoin/getApplyIssueNftInfoByDenomId?";
        Map<String,String> paramsInfo = new HashMap<>();
        paramsInfo.put("denomId",denomId);
        JSONObject jsonObject1 = dataWebService.hutoolPostWebService(urlInfo, paramsInfo, null, null);
        if(Constant.SUCCESS_CODE == (Integer) jsonObject1.get("code")){
            //{\"nftApplyId\":1,\"dawName\":\"测试001\",\"chainCode\":\"dt\",\"applyNum\":2,\"denomId\":\"denomccfcab7b33c04f2ebdb7041229a27593\",\"userId\":70,\"imgUrl\":\"https://test-dtc-minio.dtchain.net/mall4j/index.gltf\",\"mintType\":\"0\",\"createTime\":\"2023-10-16 06:41:30\",\"objUrl\":\"https://test-dtc-minio.dtchain.net/mall4j/index.gltf\",\"objType\":\"1\",\"channelCode\":\"dtcmall\",\"status\":\"3\",\"surplusIssueNum\":0}
            if(!ObjectUtil.isNull(jsonObject1.get("data"))){
                RedisUtil.set("applyIssue::"+denomId,jsonObject1.get("data"),0);
            }
        }
    }
}
